/*
 Copyright (c) 2024 HigginsSoft, Alexander Higgins - https://github.com/alexhiggins732/ 

 Copyright (c) 2018, Brock Allen & Dominick Baier. All rights reserved.

 Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 
 Source code and license this software can be found 

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.
*/

namespace IdentityServer8.Configuration;

internal class ConfigureInternalCookieOptions : IConfigureNamedOptions<CookieAuthenticationOptions>
{
    private readonly IdentityServerOptions _idsrv;

    public ConfigureInternalCookieOptions(IdentityServerOptions idsrv)
    {
        _idsrv = idsrv;
    }

    public void Configure(CookieAuthenticationOptions options)
    {
    }

    public void Configure(string name, CookieAuthenticationOptions options)
    {
        if (name == IdentityServerConstants.DefaultCookieAuthenticationScheme)
        {
            options.SlidingExpiration = _idsrv.Authentication.CookieSlidingExpiration;
            options.ExpireTimeSpan = _idsrv.Authentication.CookieLifetime;
            options.Cookie.Name = IdentityServerConstants.DefaultCookieAuthenticationScheme;
            options.Cookie.IsEssential = true;
            options.Cookie.SameSite = _idsrv.Authentication.CookieSameSiteMode;

            options.LoginPath = ExtractLocalUrl(_idsrv.UserInteraction.LoginUrl);
            options.LogoutPath = ExtractLocalUrl(_idsrv.UserInteraction.LogoutUrl);
            if (_idsrv.UserInteraction.LoginReturnUrlParameter != null)
            {
                options.ReturnUrlParameter = _idsrv.UserInteraction.LoginReturnUrlParameter;
            }
        }

        if (name == IdentityServerConstants.ExternalCookieAuthenticationScheme)
        {
            options.Cookie.Name = IdentityServerConstants.ExternalCookieAuthenticationScheme;
            options.Cookie.IsEssential = true;
            // https://github.com/alexhiggins732/IdentityServer8/issues/2595
            // need to set None because iOS 12 safari considers the POST back to the client from the 
            // IdP as not safe, so cookies issued from response (with lax) then should not be honored.
            // so we need to make those cookies issued without same-site, thus the browser will
            // hold onto them and send on the next redirect to the callback page.
            // see: https://brockallen.com/2019/01/11/same-site-cookies-asp-net-core-and-external-authentication-providers/
            options.Cookie.SameSite = _idsrv.Authentication.CookieSameSiteMode;
        }
    }

    private static string ExtractLocalUrl(string url)
    {
        if (url.IsLocalUrl())
        {
            if (url.StartsWith("~/"))
            {
                url = url.Substring(1);
            }

            return url;
        }

        return null;
    }
}

internal class PostConfigureInternalCookieOptions : IPostConfigureOptions<CookieAuthenticationOptions>
{
    private readonly IdentityServerOptions _idsrv;
    private readonly IOptions<Microsoft.AspNetCore.Authentication.AuthenticationOptions> _authOptions;
    private readonly ILogger _logger;

    public PostConfigureInternalCookieOptions(
        IdentityServerOptions idsrv,
        IOptions<Microsoft.AspNetCore.Authentication.AuthenticationOptions> authOptions,
        ILoggerFactory loggerFactory)
    {
        _idsrv = idsrv;
        _authOptions = authOptions;
        _logger = loggerFactory.CreateLogger("IdentityServer8.Startup");
    }

    public void PostConfigure(string name, CookieAuthenticationOptions options)
    {
        var scheme = _idsrv.Authentication.CookieAuthenticationScheme ??
            _authOptions.Value.DefaultAuthenticateScheme ??
            _authOptions.Value.DefaultScheme;

        if (name == scheme)
        {
            _idsrv.UserInteraction.LoginUrl = _idsrv.UserInteraction.LoginUrl ?? options.LoginPath;
            _idsrv.UserInteraction.LoginReturnUrlParameter = _idsrv.UserInteraction.LoginReturnUrlParameter ?? options.ReturnUrlParameter;
            _idsrv.UserInteraction.LogoutUrl = _idsrv.UserInteraction.LogoutUrl ?? options.LogoutPath;

            _logger.LogDebug("Login Url: {url}", _idsrv.UserInteraction.LoginUrl);
            _logger.LogDebug("Login Return Url Parameter: {param}", _idsrv.UserInteraction.LoginReturnUrlParameter);
            _logger.LogDebug("Logout Url: {url}", _idsrv.UserInteraction.LogoutUrl);

            _logger.LogDebug("ConsentUrl Url: {url}", _idsrv.UserInteraction.ConsentUrl);
            _logger.LogDebug("Consent Return Url Parameter: {param}", _idsrv.UserInteraction.ConsentReturnUrlParameter);

            _logger.LogDebug("Error Url: {url}", _idsrv.UserInteraction.ErrorUrl);
            _logger.LogDebug("Error Id Parameter: {param}", _idsrv.UserInteraction.ErrorIdParameter);
        }
    }
}
